import sys
import sqlite3
import datetime

from PyQt5.QtGui import QTextCharFormat, QFont, QIcon
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QDate, QSize


# 初始化数据库
def init_db():
    conn = sqlite3.connect('check_system.db')
    cursor = conn.cursor()

    # 创建计划表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS plans (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            start_date DATE NOT NULL,
            end_date DATE NOT NULL,
            schedule_type INTEGER NOT NULL,
            weekly_days TEXT
        )
    ''')

    # 创建任务表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            plan_id INTEGER NOT NULL,
            task_name TEXT NOT NULL,
            FOREIGN KEY(plan_id) REFERENCES plans(id)
        )
    ''')

    # 创建计划日期表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS plan_dates (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            plan_id INTEGER NOT NULL,
            date DATE NOT NULL,
            FOREIGN KEY(plan_id) REFERENCES plans(id)
        )
    ''')

    # 创建打卡记录表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS check_records (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            plan_id INTEGER NOT NULL,
            task_id INTEGER NOT NULL,
            date DATE NOT NULL,
            completed INTEGER DEFAULT 0,
            FOREIGN KEY(plan_id) REFERENCES plans(id),
            FOREIGN KEY(task_id) REFERENCES tasks(id)
        )
    ''')

    conn.commit()
    conn.close()


init_db()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("打卡系统")
        self.setWindowIcon(QIcon("./icons/打卡.png"))  # 设置窗体图标
        # 调整窗口大小和位置
        self.setGeometry(100, 100, 1024, 768)
        self.init_ui()
        self.load_plans()

    def init_ui(self):
        # 创建工具栏
        toolbar = QToolBar()
        toolbar.setIconSize(QSize(32, 32))  # 增大工具栏图标大小
        self.addToolBar(toolbar)

        # 添加计划按钮
        new_plan_action = QAction(QIcon("icons/新增.png"), "新建计划", self)  # 添加图标
        new_plan_action.triggered.connect(self.show_new_plan_dialog)
        toolbar.addAction(new_plan_action)

        # 删除计划按钮
        delete_plan_action = QAction(QIcon("icons/删除.png"), "删除计划", self)  # 添加图标
        delete_plan_action.triggered.connect(self.delete_selected_plan)
        toolbar.addAction(delete_plan_action)

        # 刷新按钮
        refresh_action = QAction(QIcon("icons/刷新.png"), "刷新", self)  # 添加图标
        refresh_action.triggered.connect(self.load_plans)
        toolbar.addAction(refresh_action)

        # 计划列表
        self.plan_table = QTableWidget()
        self.plan_table.setColumnCount(6)
        self.plan_table.setHorizontalHeaderLabels(["ID", "计划名称", "开始日期", "结束日期", "完成度", "状态"])
        self.plan_table.setAlternatingRowColors(True)  # 交替行颜色
        self.plan_table.setEditTriggers(QAbstractItemView.NoEditTriggers)  # 禁止编辑
        self.plan_table.setSelectionBehavior(QAbstractItemView.SelectRows)  # 整行选择
        self.plan_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  # 列宽自适应
        self.plan_table.verticalHeader().setVisible(False)  # 隐藏行号
        self.plan_table.setStyleSheet("QTableWidget { font-size: 14px; }")  # 设置字体大小

        self.plan_table.doubleClicked.connect(self.show_plan_detail)

        # 设置中心部件
        self.setCentralWidget(self.plan_table)

    def delete_selected_plan(self):
        selected_rows = self.plan_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "错误", "请先选择一个计划")
            return

        reply = QMessageBox.question(self, '确认', '确定要删除选中的计划吗？',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            for index in sorted(selected_rows, reverse=True):
                plan_id = int(self.plan_table.item(index.row(), 0).text())
                conn = sqlite3.connect('check_system.db')
                cursor = conn.cursor()
                try:
                    cursor.execute('BEGIN')
                    # 删除关联数据（按外键顺序）
                    cursor.execute('DELETE FROM check_records WHERE plan_id=?', (plan_id,))
                    cursor.execute('DELETE FROM plan_dates WHERE plan_id=?', (plan_id,))
                    cursor.execute('DELETE FROM tasks WHERE plan_id=?', (plan_id,))
                    cursor.execute('DELETE FROM plans WHERE id=?', (plan_id,))
                    conn.commit()
                except Exception as e:
                    conn.rollback()
                    QMessageBox.critical(self, "错误", f"删除失败: {str(e)}")
                finally:
                    conn.close()
            self.load_plans()

    def load_plans(self):
        self.plan_table.setRowCount(0)
        conn = sqlite3.connect('check_system.db')
        cursor = conn.cursor()
        cursor.execute('SELECT id, name, start_date, end_date FROM plans')
        plans = cursor.fetchall()
        for row_idx, plan in enumerate(plans):
            self.plan_table.insertRow(row_idx)
            plan_id, name, start_date, end_date = plan

            # 计算完成度
            cursor.execute('''
                SELECT COUNT(*) FROM check_records 
                WHERE plan_id=? AND completed=1
            ''', (plan_id,))
            completed = cursor.fetchone()[0]

            cursor.execute('''
                SELECT COUNT(*) FROM check_records 
                WHERE plan_id=?
            ''', (plan_id,))
            total = cursor.fetchone()[0]

            progress = f"{completed}/{total}" if total > 0 else "0/0"

            # 设置当前时间状态
            current_date = datetime.date.today().strftime('%Y-%m-%d')
            status = ""
            if start_date > current_date:
                status = "未开始"
            elif end_date < current_date:
                status = "已结束"
            else:
                status = "进行中"

            # 填充表格
            self.plan_table.setItem(row_idx, 0, QTableWidgetItem(str(plan_id)))
            self.plan_table.setItem(row_idx, 1, QTableWidgetItem(name))
            self.plan_table.setItem(row_idx, 2, QTableWidgetItem(start_date))
            self.plan_table.setItem(row_idx, 3, QTableWidgetItem(end_date))
            self.plan_table.setItem(row_idx, 4, QTableWidgetItem(progress))  # 完成度
            self.plan_table.setItem(row_idx, 5, QTableWidgetItem(status))  # 状态

        conn.close()

    def show_new_plan_dialog(self):
        dialog = NewPlanDialog(self)
        if dialog.exec_() == QDialog.Accepted:
            self.load_plans()

    def show_plan_detail(self, index):
        plan_id = int(self.plan_table.item(index.row(), 0).text())
        self.detail_window = PlanDetailWindow(plan_id)
        self.detail_window.show()


class NewPlanDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("新建计划")
        self.setWindowIcon(QIcon("./icons/打卡.png"))  # 设置窗体图标
        self.setMinimumSize(600, 400)
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # 计划名称
        self.name_edit = QLineEdit()
        layout.addWidget(QLabel("计划名称:"))
        layout.addWidget(self.name_edit)

        # 日期范围
        date_layout = QHBoxLayout()
        self.start_date = QDateEdit()
        self.start_date.setCalendarPopup(True)
        self.end_date = QDateEdit()
        self.end_date.setCalendarPopup(True)

        # 设置默认日期
        current_date = QDate.currentDate()
        one_month_ago = current_date.addMonths(1)
        self.start_date.setDate(current_date)  # 默认设为当前日期
        self.end_date.setDate(one_month_ago)  # 默认设为当前日期退后一个月

        date_layout.addWidget(QLabel("开始日期:"))
        date_layout.addWidget(self.start_date)
        date_layout.addWidget(QLabel("结束日期:"))
        date_layout.addWidget(self.end_date)
        layout.addLayout(date_layout)

        # 计划类型
        self.schedule_type = QTabWidget()

        # 跳过周末
        self.skip_weekend_tab = QWidget()
        self.skip_weekend_check = QCheckBox("跳过周末")
        tab_layout1 = QVBoxLayout()
        tab_layout1.addWidget(self.skip_weekend_check)
        self.skip_weekend_tab.setLayout(tab_layout1)

        # 每周几天
        self.weekly_tab = QWidget()
        self.days = [QCheckBox(day) for day in ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]]
        tab_layout2 = QHBoxLayout()
        for cb in self.days:
            tab_layout2.addWidget(cb)
        self.weekly_tab.setLayout(tab_layout2)

        # 自定义日期
        self.custom_tab = QWidget()
        self.calendar = QCalendarWidget()
        self.selected_dates = []
        self.date_list = QListWidget()
        add_btn = QPushButton("添加日期")
        add_btn.clicked.connect(self.add_date)
        tab_layout3 = QVBoxLayout()
        tab_layout3.addWidget(self.calendar)
        tab_layout3.addWidget(add_btn)
        tab_layout3.addWidget(self.date_list)
        self.custom_tab.setLayout(tab_layout3)

        self.schedule_type.addTab(self.skip_weekend_tab, "跳过周末")
        self.schedule_type.addTab(self.weekly_tab, "每周几天")
        self.schedule_type.addTab(self.custom_tab, "自定义日期")
        layout.addWidget(self.schedule_type)

        # 任务管理
        self.tasks = QListWidget()
        add_task_btn = QPushButton("添加任务")
        add_task_btn.clicked.connect(self.add_task)
        task_layout = QHBoxLayout()
        task_layout.addWidget(self.tasks)
        task_layout.addWidget(add_task_btn)
        layout.addWidget(QLabel("每日任务:"))
        layout.addLayout(task_layout)

        # 按钮
        btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn_box.accepted.connect(self.accept)
        btn_box.rejected.connect(self.reject)
        layout.addWidget(btn_box)

        self.setLayout(layout)

    def add_task(self):
        task, ok = QInputDialog.getText(self, "添加任务", "请输入任务名称:")
        if ok and task:
            self.tasks.addItem(task)

    def add_date(self):
        date = self.calendar.selectedDate().toString("yyyy-MM-dd")
        if date not in self.selected_dates:
            self.selected_dates.append(date)
            self.date_list.addItem(date)

    def accept(self):
        # 数据验证
        if not self.name_edit.text():
            QMessageBox.warning(self, "错误", "请输入计划名称")
            return

        start_date = self.start_date.date().toString("yyyy-MM-dd")
        end_date = self.end_date.date().toString("yyyy-MM-dd")
        if QDate.fromString(start_date, "yyyy-MM-dd") > QDate.fromString(end_date, "yyyy-MM-dd"):
            QMessageBox.warning(self, "错误", "结束日期不能早于开始日期")
            return

        if self.tasks.count() == 0:
            QMessageBox.warning(self, "错误", "请至少添加一个任务")
            return

        # 获取计划类型
        schedule_type = self.schedule_type.currentIndex()
        weekly_days = []
        custom_dates = []

        if schedule_type == 0 and not self.skip_weekend_check.isChecked():
            QMessageBox.warning(self, "错误", "请选择跳过周末")
            return
        elif schedule_type == 1:
            weekly_days = [i for i, cb in enumerate(self.days) if cb.isChecked()]
            if not weekly_days:
                QMessageBox.warning(self, "错误", "请选择至少一个工作日")
                return
        elif schedule_type == 2:
            custom_dates = self.selected_dates
            if not custom_dates:
                QMessageBox.warning(self, "错误", "请添加至少一个自定义日期")
                return

        # 保存到数据库
        conn = sqlite3.connect('check_system.db')
        cursor = conn.cursor()

        try:
            # 插入计划
            cursor.execute('''
                INSERT INTO plans (name, start_date, end_date, schedule_type, weekly_days)
                VALUES (?, ?, ?, ?, ?)
            ''', (
                self.name_edit.text(),
                start_date,
                end_date,
                schedule_type,
                ','.join(map(str, weekly_days)) if weekly_days else None
            ))
            plan_id = cursor.lastrowid

            # 插入任务
            tasks = []
            for i in range(self.tasks.count()):
                task = self.tasks.item(i).text()
                cursor.execute('''
                    INSERT INTO tasks (plan_id, task_name) VALUES (?, ?)
                ''', (plan_id, task))
                tasks.append(cursor.lastrowid)

            # 生成日期
            dates = []
            if schedule_type == 0:
                current = QDate.fromString(start_date, "yyyy-MM-dd")
                end = QDate.fromString(end_date, "yyyy-MM-dd")
                while current <= end:
                    if current.dayOfWeek() < 6:  # 1-5为周一到周五
                        dates.append(current.toString("yyyy-MM-dd"))
                    current = current.addDays(1)
            elif schedule_type == 1:
                current = QDate.fromString(start_date, "yyyy-MM-dd")
                end = QDate.fromString(end_date, "yyyy-MM-dd")
                while current <= end:
                    if (current.dayOfWeek() - 1) in weekly_days:
                        dates.append(current.toString("yyyy-MM-dd"))
                    current = current.addDays(1)
            else:
                dates = custom_dates

            # 插入日期
            for date in dates:
                cursor.execute('''
                    INSERT INTO plan_dates (plan_id, date) VALUES (?, ?)
                ''', (plan_id, date))

            # 生成打卡记录
            for date in dates:
                for task_id in tasks:
                    cursor.execute('''
                        INSERT INTO check_records (plan_id, task_id, date)
                        VALUES (?, ?, ?)
                    ''', (plan_id, task_id, date))

            conn.commit()
            QMessageBox.information(self, "成功", "计划创建成功！")
            super().accept()
        except Exception as e:
            conn.rollback()
            QMessageBox.critical(self, "错误", f"保存失败: {str(e)}")
        finally:
            conn.close()


class PlanDetailWindow(QWidget):
    def __init__(self, plan_id):
        super().__init__()
        self.plan_id = plan_id
        self.selected_date = QDate.currentDate().toString("yyyy-MM-dd")  # 初始化为当前日期
        self.setWindowTitle(f"计划详情 - {self.selected_date} - 计划名称待加载")  # 初始化标题
        self.setWindowIcon(QIcon("./icons/打卡.png"))  # 设置窗体图标
        # 调整窗口大小和位置
        self.setGeometry(200, 200, 1024, 768)
        self.init_ui()
        self.load_data()

    def init_ui(self):
        layout = QVBoxLayout()

        # 日历视图
        self.calendar = QCalendarWidget()
        self.calendar.setGridVisible(True)
        self.calendar.setStyleSheet("QCalendarWidget { font-size: 16px; }")  # 设置字体大小
        self.calendar.setMinimumHeight(400)  # 增加日历高度
        self.calendar.clicked.connect(self.date_changed)
        layout.addWidget(self.calendar)

        # 任务列表
        self.task_table = QTableWidget()
        self.task_table.setColumnCount(3)
        self.task_table.setHorizontalHeaderLabels(["任务", "完成状态", "操作"])
        self.task_table.setAlternatingRowColors(True)  # 交替行颜色
        self.task_table.setEditTriggers(QAbstractItemView.NoEditTriggers)  # 禁止编辑
        self.task_table.setSelectionBehavior(QAbstractItemView.SelectRows)  # 整行选择
        self.task_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  # 列宽自适应
        self.task_table.verticalHeader().setVisible(False)  # 隐藏行号
        self.task_table.setStyleSheet("QTableWidget { font-size: 14px; }")  # 设置字体大小

        layout.addWidget(self.task_table)

        self.setLayout(layout)

    def date_changed(self, date):
        self.selected_date = date.toString("yyyy-MM-dd")
        self.setWindowTitle(f"计划详情 - {self.selected_date} - {self.windowTitle().split(' - ')[-1]}")
        self.update_task_table(self.selected_date)

    def update_task_table(self, selected_date):
        self.task_table.setRowCount(0)
        conn = sqlite3.connect('check_system.db')
        cursor = conn.cursor()

        for task_id, task_name in self.tasks:
            row = self.task_table.rowCount()
            self.task_table.insertRow(row)

            # 任务名称
            self.task_table.setItem(row, 0, QTableWidgetItem(task_name))

            # 完成状态
            cursor.execute('''
                SELECT completed FROM check_records 
                WHERE plan_id=? AND task_id=? AND date=?
            ''', (self.plan_id, task_id, selected_date))
            result = cursor.fetchone()

            check_state = Qt.Checked if result and result[0] else Qt.Unchecked
            status_item = QTableWidgetItem()
            status_item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
            status_item.setData(Qt.CheckStateRole, check_state)

            # 设置文本居中（虽然不显示文字，但会影响布局）
            status_item.setTextAlignment(Qt.AlignCenter)
            self.task_table.setItem(row, 1, status_item)

            # 保存按钮
            btn = QPushButton("更新")
            btn.clicked.connect(lambda _, p=self.plan_id, t=task_id, d=selected_date:
                                self.update_status(p, t, d))
            self.task_table.setCellWidget(row, 2, btn)

        conn.close()

    def load_data(self):
        conn = sqlite3.connect('check_system.db')
        cursor = conn.cursor()

        # 获取计划信息
        cursor.execute('SELECT name, start_date, end_date FROM plans WHERE id=?', (self.plan_id,))
        plan_name, start_date, end_date = cursor.fetchone()
        self.setWindowTitle(f"计划详情 - {self.selected_date} - {plan_name}")

        # 设置日历的最小和最大日期
        self.calendar.setMinimumDate(QDate.fromString(start_date, "yyyy-MM-dd"))
        self.calendar.setMaximumDate(QDate.fromString(end_date, "yyyy-MM-dd"))

        # 获取所有任务
        cursor.execute('SELECT id, task_name FROM tasks WHERE plan_id=?', (self.plan_id,))
        self.tasks = cursor.fetchall()

        # 获取所有日期
        cursor.execute('SELECT date FROM plan_dates WHERE plan_id=?', (self.plan_id,))
        self.dates = [row[0] for row in cursor.fetchall()]

        conn.close()

        # 更新任务表格和日历样式
        self.update_task_table(self.selected_date)
        self.update_calendar()  # 新增：更新日历颜色

    def update_calendar(self):
        # 获取当前计划的所有日期
        conn = sqlite3.connect('check_system.db')
        cursor = conn.cursor()

        # 查询所有与该计划相关的打卡记录
        cursor.execute('''
            SELECT date, task_id, completed FROM check_records WHERE plan_id=?
        ''', (self.plan_id,))
        records = cursor.fetchall()

        # 按日期组织数据
        from collections import defaultdict
        date_tasks = defaultdict(list)
        for date, task_id, completed in records:
            date_tasks[date].append(completed)

        current_date = datetime.date.today().strftime('%Y-%m-%d')

        # 清除之前的格式
        default_format = QTextCharFormat()

        for date_str in date_tasks:
            date = QDate.fromString(date_str, "yyyy-MM-dd")

            # 创建格式
            fmt = QTextCharFormat()

            if date_str == current_date:  # 当天有任务 → 蓝色边框
                fmt.setBackground(Qt.blue)
                fmt.setForeground(Qt.white)
            elif date_str > current_date:  # 未来日期 → 灰色
                fmt.setBackground(Qt.gray)
                fmt.setForeground(Qt.black)
            else:
                tasks = date_tasks[date_str]
                if all(tasks):  # 全部完成 → 绿色
                    fmt.setBackground(Qt.green)
                elif any(tasks):  # 部分完成 → 黄色
                    fmt.setBackground(Qt.yellow)
                else:  # 全未完成 → 红色
                    fmt.setBackground(Qt.red)
                fmt.setForeground(Qt.black)

            self.calendar.setDateTextFormat(date, fmt)

        conn.close()

    def update_status(self, plan_id, task_id, date):
        conn = sqlite3.connect('check_system.db')
        cursor = conn.cursor()

        # 获取当前状态
        cursor.execute('''
            SELECT completed FROM check_records 
            WHERE plan_id=? AND task_id=? AND date=?
        ''', (plan_id, task_id, date))
        result = cursor.fetchone()
        current = result[0] if result else 0  # 如果没有记录，默认设为 0（未完成）

        # 切换状态
        new_status = 0 if current else 1
        cursor.execute('''
            UPDATE check_records SET completed=? 
            WHERE plan_id=? AND task_id=? AND date=?
        ''', (new_status, plan_id, task_id, date))

        conn.commit()
        conn.close()
        self.update_task_table(date)
        QMessageBox.information(self, "成功", "状态已更新！")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


# pyinstaller --onefile --noconsole --icon=./icons/打卡.png --name "计划打卡 V 1.0.0"  main.py